home *** CD-ROM | disk | FTP | other *** search
/ Download Now 8 / Download Now V8.iso / Program / InternetTools / ApacheWebServer1.3.6 / apache_1_3_6_win32.exe / _SETUP.1 / registry.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-23  |  11.2 KB  |  396 lines

  1. /*
  2.  * Functions to handle interacting with the Win32 registry
  3.  */
  4.  
  5. /*
  6.  * Apache registry key structure
  7.  *
  8.  * Apache's registry information is stored in the HKEY_LOCAL_MACHINE
  9.  * key, under
  10.  *
  11.  *  HKLM\SOFTWARE\Apache Group\Apache\version
  12.  *
  13.  * These keys are defined in this file. The definition of the "version" part
  14.  * will need updating each time Apache moves from beta to non-beta or from a
  15.  * release to a development or beta version.
  16.  */
  17.  
  18. #include <windows.h>
  19. #include <stdio.h>
  20.  
  21. #include "httpd.h"
  22. #include "http_log.h"
  23.  
  24. /* Define where the Apache values are stored in the registry. In general
  25.  * VERSION will be the same across all beta releases for a particular
  26.  * major release, but will change when the final release is made.
  27.  */
  28.  
  29. #define VENDOR   "Apache Group"
  30. #define SOFTWARE "Apache"
  31. #define VERSION  "1.3.6"
  32.  
  33. #define REGKEY "SOFTWARE\\" VENDOR "\\" SOFTWARE "\\" VERSION
  34.  
  35. /*
  36.  * The Windows API registry key functions don't set the last error
  37.  * value (the windows equivalent of errno). So we need to set it
  38.  * with SetLastError() before calling the aplog_error() function.
  39.  * Because this is common, let's have a macro.
  40.  */
  41. #define do_error(rv,fmt,arg) do { \
  42.     SetLastError(rv); \
  43.     ap_log_error(APLOG_MARK, APLOG_WIN32ERROR|APLOG_ERR, NULL, fmt,arg); \
  44.     } while (0);
  45.  
  46. /*
  47.  * Get the data for registry key value. This is a generic function that
  48.  * can either get a value into a caller-supplied buffer, or it can
  49.  * allocate space for the value from the pass-in pool. It will normally
  50.  * be used by other functions within this file to get specific key values
  51.  * (e.g. registry_get_server_root()). This function returns a number of
  52.  * different error statuses, allowing the caller to differentiate
  53.  * between a key or value not existing and other kinds of errors. Depending
  54.  * on the type of data being obtained the caller can then either ignore
  55.  * the key-not-existing error, or treat it as a real error.
  56.  *
  57.  * If ppValue is NULL, allocate space for the value and return it in
  58.  * *pValue. The return value is the number of bytes in the value.
  59.  * The first argument is the pool to use to allocate space for the value.
  60.  *
  61.  * If pValue is not NULL, assume it is a buffer of nSizeValue bytes,
  62.  * and write the value into the buffer. The return value is the number
  63.  * of bytes in the value (so if the return value is greater than
  64.  * the supplied nSizeValue, the caller knows that *pValue is truncated).
  65.  * The pool argument is ignored.
  66.  *
  67.  * The return value is the number of bytes in the successfully retreived
  68.  * key if everything worked, or:
  69.  *
  70.  *  -1 the key does not exists
  71.  *  -2 if out of memory during the function
  72.  *  -3 if the buffer specified by *pValue/nSizeValue was not large enough 
  73.  *     for the value.
  74.  *  -4 if an error occurred
  75.  *
  76.  * If the return value is negative a message will be logged to the error
  77.  * log (aplog_error) function. If the return value is -2, -3 or -4 the message
  78.  * will be logged at priority "error", while if the return value is -1 the
  79.  * message will be logged at priority "warning".
  80.  */
  81.  
  82. static int ap_registry_get_key_int(pool *p, char *key, char *pBuffer, int nSizeBuffer, char **ppValue)
  83. {
  84.     long rv;
  85.     HKEY hKey;
  86.     char *pValue;
  87.     int nSize;
  88.     int retval;
  89.  
  90.     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  91.               REGKEY,
  92.               0,
  93.               KEY_READ,
  94.               &hKey);
  95.  
  96.     if (rv == ERROR_FILE_NOT_FOUND) {
  97.     ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,NULL,
  98.         "Registry does not contain key " REGKEY);
  99.     return -1;
  100.     }
  101.     if (rv != ERROR_SUCCESS) {
  102.     do_error(rv, "RegOpenKeyEx HKLM\\" REGKEY,
  103.          NULL);
  104.     return -4;
  105.     }
  106.  
  107.     if (pBuffer == NULL) {
  108.     /* Find the size required for the data by passing NULL as the buffer
  109.      * pointer. On return nSize will contain the size required for the
  110.      * buffer if the return value is ERROR_SUCCESS.
  111.      */
  112.     rv = RegQueryValueEx(hKey, 
  113.                  key,        /* key name */
  114.                  NULL,        /* reserved */
  115.                  NULL,        /* type */
  116.                  NULL,        /* for value */
  117.                  &nSize);        /* for size of "value" */
  118.  
  119.     if (rv != ERROR_SUCCESS) {
  120.         do_error(rv, "RegQueryValueEx(key %s)", key);
  121.         return -1;
  122.     }
  123.  
  124.     pValue = ap_palloc(p, nSize);
  125.     *ppValue = pValue;
  126.     if (!pValue) {
  127.         /* Eek, out of memory, probably not worth trying to carry on,
  128.          * but let's give it a go
  129.          */
  130.         ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,NULL,
  131.         "Error getting registry key: out of memory");
  132.         return -2;
  133.     }
  134.     }
  135.     else {
  136.     /* Get the value into the existing buffer of length nSizeBuffer */
  137.     pValue = pBuffer;
  138.     nSize = nSizeBuffer;
  139.     }
  140.  
  141.     rv = RegQueryValueEx(hKey, 
  142.              key,        /* key name */
  143.              NULL,        /* reserved */
  144.              NULL,        /* type */
  145.              pValue,        /* for value */
  146.              &nSize);        /* for size of "value" */
  147.  
  148.     retval = 0;        /* Return value */
  149.  
  150.     if (rv == ERROR_FILE_NOT_FOUND) {
  151.     ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,NULL,
  152.         "Registry does not contain value " REGKEY "\\%s", key);
  153.     retval = -1;
  154.     }
  155.     else if (rv == ERROR_MORE_DATA) {
  156.     /* This should only happen if we got passed a pre-existing buffer
  157.      * (pBuffer, nSizeBuffer). But I suppose it could also happen if we
  158.      * allocate a buffer if another process changed the length of the
  159.      * value since we found out its length above. Umm.
  160.      */
  161.     ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,NULL,
  162.         "Error getting registry value %s: buffer not big enough", key);
  163.     retval = -3;
  164.     }
  165.     else if (rv != ERROR_SUCCESS) {
  166.     do_error(rv, "RegQueryValueEx(key %s)", key);
  167.     retval = -4;
  168.     }
  169.  
  170.     rv = RegCloseKey(hKey);
  171.     if (rv != ERROR_SUCCESS) {
  172.     do_error(rv, "RegCloseKey HKLM\\" REGKEY, NULL);
  173.     if (retval == 0) {
  174.         /* Keep error status from RegQueryValueEx, if any */
  175.         retval = -4;  
  176.     }
  177.     }
  178.  
  179.     return retval < 0 ? retval : nSize;
  180. }
  181.  
  182. /*
  183.  * Get the server root from the registry into 'dir' which is
  184.  * size bytes long. Returns 0 if the server root was found
  185.  * or if the serverroot key does not exist (in which case
  186.  * dir will contain an empty string), or -1 if there was
  187.  * an error getting the key.
  188.  */
  189.  
  190. int ap_registry_get_server_root(pool *p, char *dir, int size)
  191. {
  192.     int rv;
  193.  
  194.     rv = ap_registry_get_key_int(p, "ServerRoot", dir, size, NULL);
  195.     if (rv < 0) {
  196.     dir[0] = '\0';
  197.     }
  198.  
  199.     return (rv < -1) ? -1 : 0;
  200. }
  201.  
  202. /**********************************************************************
  203.  * The rest of this file deals with storing keys or values in the registry
  204.  */
  205.  
  206. /*
  207.  * ap_registry_create_apache_key() creates the Apache registry key
  208.  * (HLKM\SOFTWARE\Apache Group\Apache\version, as defined at the start
  209.  * of this file), if it does not already exist. It will be called by
  210.  * ap_registry_store_key_int() if it cannot open this key. This 
  211.  * function is intended to be called by ap_registry_store_key_int() if
  212.  * the Apache key does not exist when it comes to store a data item.
  213.  *
  214.  * Returns 0 on success or -1 on error. If -1 is returned, the error will
  215.  * already have been logged.
  216.  */
  217.  
  218. static int ap_registry_create_apache_key(void)
  219. {
  220.     static char *keys[] = 
  221.     { "SOFTWARE",
  222.     VENDOR,
  223.     SOFTWARE,
  224.     VERSION,
  225.     NULL
  226.     };
  227.     int index;
  228.     HKEY hKey;
  229.     HKEY hKeyNext;
  230.     int retval;
  231.     int rv;
  232.  
  233.     hKey = HKEY_LOCAL_MACHINE;
  234.     index = 0;
  235.     retval = 0;
  236.  
  237.     /* Walk the tree, creating at each stage if necessary */
  238.     while (keys[index]) {
  239.     int result;
  240.  
  241.     rv = RegCreateKeyEx(hKey,
  242.                 keys[index], /* subkey */
  243.                 0,             /* reserved */
  244.                 NULL,        /* class */
  245.                 REG_OPTION_NON_VOLATILE,
  246.                 KEY_WRITE,
  247.                 NULL,
  248.                 &hKeyNext,
  249.                 &result);
  250.     if (rv != ERROR_SUCCESS) {
  251.         do_error(rv, "RegCreateKeyEx(%s)", keys[index]);
  252.         retval = -4;
  253.     }
  254.  
  255.     /* Close the old key */
  256.     rv = RegCloseKey(hKey);
  257.     if (rv != ERROR_SUCCESS) {
  258.         do_error(rv, "RegCloseKey", NULL);
  259.         if (retval == 0) {
  260.         /* Keep error status from RegCreateKeyEx, if any */
  261.         retval = -4;  
  262.         }
  263.     }
  264.  
  265.     if (retval) {
  266.         break;
  267.     }
  268.  
  269.     hKey = hKeyNext;
  270.     index++;
  271.     }
  272.  
  273.     if (keys[index] == NULL) {
  274.     /* Close the final key we opened, if we walked the entire
  275.      * tree
  276.      */
  277.     rv = RegCloseKey(hKey);
  278.     if (rv != ERROR_SUCCESS) {
  279.         do_error(rv, "RegCloseKey", NULL);
  280.         if (retval == 0) {
  281.         /* Keep error status from RegCreateKeyEx, if any */
  282.         retval = -4;  
  283.         }
  284.     }
  285.     }
  286.  
  287.     return retval;
  288. }
  289.  
  290. /*
  291.  * ap_registry_store_key_int() stores a value name and value under the
  292.  * Apache registry key. If the Apache key does not exist it is created
  293.  * first. This function is intended to be called from a wrapper function
  294.  * in this file to set particular data values, such as 
  295.  * ap_registry_set_server_root() below.
  296.  *
  297.  * Returns 0 if the value name and data was stored successfully, or
  298.  * returns -1 if the Apache key does not exist (since we try to create 
  299.  * this key, this should never happen), or -4 if any other error occurred
  300.  * (these values are consistent with ap_registry_get_key_int()).
  301.  * If the return value is negative then the error will already have been
  302.  * logged via aplog_error().
  303.  */
  304.  
  305. static int ap_registry_store_key_int(char *key, DWORD type, void *value, int value_size)
  306. {
  307.     long rv;
  308.     HKEY hKey;
  309.     int retval;
  310.  
  311.     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  312.               REGKEY,
  313.               0,
  314.                KEY_WRITE,
  315.               &hKey);
  316.  
  317.     if (rv == ERROR_FILE_NOT_FOUND) {
  318.     /* Key could not be opened -- try to create it 
  319.      */
  320.     if (ap_registry_create_apache_key() < 0) {
  321.         /* Creation failed (error already reported) */
  322.         return -4;
  323.     }
  324.     
  325.     /* Now it has been created we should be able to open it
  326.      */
  327.     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  328.           REGKEY,
  329.           0,
  330.            KEY_WRITE,
  331.           &hKey);
  332.  
  333.     if (rv == ERROR_FILE_NOT_FOUND) {
  334.         ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,NULL,
  335.         "Registry does not contain key " REGKEY " after creation");
  336.  
  337.         return -1;
  338.     }
  339.     }
  340.  
  341.     if (rv != ERROR_SUCCESS) {
  342.     do_error(rv, "RegOpenKeyEx HKLM\\" REGKEY,
  343.          NULL);
  344.     return -4;
  345.     }
  346.  
  347.     /* Now set the value and data */
  348.     rv = RegSetValueEx(hKey, 
  349.                key,    /* value key name */
  350.                0,    /* reserved */
  351.                type,    /* type */
  352.                value,    /* value data */
  353.                (DWORD)value_size); /* for size of "value" */
  354.  
  355.     retval = 0;        /* Return value */
  356.  
  357.     if (rv != ERROR_SUCCESS) {
  358.     do_error(rv, "RegQueryValueEx(key %s)", key);
  359.     retval = -4;
  360.     }
  361.     else {
  362.     ap_log_error(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,NULL,
  363.         "Registry stored HKLM\\" REGKEY "\\%s value %s", key, 
  364.         type == REG_SZ ? value : "(not displayable)");
  365.     }
  366.  
  367.     /* Make sure we close the key even if there was an error storing
  368.      * the data
  369.      */
  370.     rv = RegCloseKey(hKey);
  371.     if (rv != ERROR_SUCCESS) {
  372.     do_error(rv, "RegCloseKey HKLM\\" REGKEY, NULL);
  373.     if (retval == 0) {
  374.         /* Keep error status from RegQueryValueEx, if any */
  375.         retval = -4;  
  376.     }
  377.     }
  378.  
  379.     return retval;
  380. }
  381.  
  382. /*
  383.  * Sets the serverroot value within the registry. Returns 0 on success
  384.  * or -1 on error. If -1 is return the error will already have been
  385.  * logged via aplog_error().
  386.  */
  387.  
  388. int ap_registry_set_server_root(char *dir)
  389. {
  390.     int rv;
  391.  
  392.     rv = ap_registry_store_key_int("ServerRoot", REG_SZ, dir, strlen(dir)+1);
  393.  
  394.     return rv < 0 ? -1 : 0;
  395. }
  396.